<?php
/**
 * WS消息处理
 */
declare(strict_types=1);

namespace Apps\Http\WebSocket;

use Swoole\WebSocket\Server;
use Swoole\WebSocket\Frame;
use Swoole\Http\Request;
use Swoole\Http\Response;
use Swoole\Coroutine;
// use Libraries\Context;
use Libraries\Config;

class WS
{
    /**
     * WS握手
     * @param Request $objRequest
     * @param Response $objResponse
     * @return boolean|response
     */
    public static function handleHandShake(Request $objRequest, Response $objResponse)
    {
        if (!Config::get('web_socket')) {
            $objResponse->end();
            return false;
        }
        $secWebSocketKey = $objRequest->header['sec-websocket-key'] ?? '';
        if (
            0 === preg_match('#^[+/0-9A-Za-z]{21}[AQgw]==$#', $secWebSocketKey)
            || 16 !== strlen(base64_decode($secWebSocketKey))
        ) {
            $objResponse->end();
            return false;
        }
        Coroutine::defer(function () use ($objRequest) {
            self::handleOpen($objRequest);
        });
        $headers = [
            'Upgrade' => 'websocket',
            'Connection' => 'Upgrade',
            'Sec-WebSocket-Accept' => base64_encode(
                sha1($secWebSocketKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true)
            ),
            'Sec-WebSocket-Version' => '13',
        ];
        if (isset($objRequest->header['sec-websocket-protocol'])) {
            $headers['Sec-WebSocket-Protocol'] = $objRequest->header['sec-websocket-protocol'];
        }
        foreach ($headers as $key => $val) {
            $objResponse->header($key, $val);
        }
        $objResponse->status(101);
        $objResponse->end();
        return true;
    }

    /**
     * WS连接打开时的处理
     * @param Request $objRequest
     */
    private static function handleOpen(Request $objRequest)
    {
        /* 这仅是示例，可以按需求自定义 */
        // ...
    }

    /**
     * WS消息的处理
     * @param Server $objServer
     * @param Frame $objFrame
     */
    public static function handleMsg(Server $objServer, Frame $objFrame)
    {
        /* 这仅是示例，可以按需求自定义 */
        // ...
    }
}
